package mkv.MyGUI;
import processing.core.*;

/**
 * MyGUICheckBox creates a checkbox object that has two marked states, checked,
 * or unchecked. It also features a label which effects the clickable area of
 * the checkbox. The central point is the middle of the checkbox.
 * 
 * @author John Beech
 */

public class MyGUICheckBox extends MyGUIObject {
    
    private boolean _checked;
    private int _boxsize; 
    private String _text;
    private boolean fixedSize; 
    /**
     * Most basic constructor, does not specify size.
     * 
     * @param root
     *            the source PApplet where graphics will be drawn to
     * @param x
     *            x coordinate, central point of checkBox
     * @param y
     *            y coordinate, central point of checkBox
     */
    public MyGUICheckBox(PApplet root, int x, int y) {
        super(root, x, y);
        _boxsize = 14;
        _width = _boxsize;
        _height = _boxsize;
        _text = "";
        fixedSize = true;
    }

    public MyGUICheckBox(PApplet root, int x, int y, int width, int height) {
        super(root, x, y);
        _width = width;
        _height = height;
        if(width >= height) {
            _boxsize = height;
        } else {
            _boxsize = width;
        }
        _text = "";
        fixedSize = true;
    }
    
    public MyGUICheckBox(PApplet root, int x, int y, String text) {
        super(root, x, y);
        _text = text;
        fixedSize = false;
    }
    
    public MyGUICheckBox(PApplet root, int x, int y, String text, int width, int height) {
        super(root, x, y);
        _text = text;
        _width = width;
        _height = height;
        if(width >= height) {
            _boxsize = height;
        } else {
            _boxsize = width;
        }
        fixedSize = true;
    }
    
    /**
     * Returns the current state (checked, or unchecked) of the checkbox 
     * @return true for checked, false for unchecked.
     */
    public boolean isChecked() {
        return _checked;
    }
    
    /**
     * Manually sets the value of the checkbox.
     * @param newState 
     */
    public void checked(boolean newState) {
        _checked = newState;
    }
    
    /**
     * Set the label text
     * 
     * @param label the new label
     */
    public void setLabel(String label) {
        _text = label;
    }
    
    /**
     * Set the label text with additional var for user to choose whether 
     * they want the size to automatically adjust based on the font, or to stay
     * at a fixed size, (compromising the hit check area) - but maintaining size.
     * 
     * @param label the new label
     * @param fixedSize stay at fixed width/height or dynamically adjust
     */
    public void setLabel(String label, boolean fixedSize) {
        _text = label;
        this.fixedSize = fixedSize;
    }
    
    public void mouseReleased() { // copied from MyGUIButton
        hover = checkForHit();
        // If mouse was previous dragged/focused (boolean dragged) from this object,
        // and the mouse was released over the target (boolean hover)
        if(hover && dragged) {
            // If mouse is released over target create ActionEvent
            MyGUIActionEvent a = new MyGUIActionEvent(this, _actionCommand);
            a.sendEvent(_root);
            // Alternate state of checkbox
            _checked = !_checked;
        }
        dragged = false;
    } 
    
    // Draw methods for this object based on states
    public void drawStates() {
        // alias to shorten _style property to st
        MyGUIStyle st = _style;
        if(_style == null) {
            st = _parent.getStyle();
        } else {
            st = _style;
        }
        // set width/height if not already
        if(!fixedSize) {
          _root.textFont(st.font, st.fontSize);
          _width = PApplet.ceil(_root.textWidth(_text))+ 4 + st.padding;
          _height = st.fontSize + 2 + st.padding;
	        // set boxsize based off width/height
	        if(_width >= _height) {
	            _boxsize = st.fontSize;
	        } else {
	            _boxsize = _width;
	        }
        }
        // set regularly used vars:
        final int halfbs = PApplet.round((float)_boxsize/2 + st.padding);
        // set text offset (used each time text is drawn to screen)
        int textVOffset = st.fontSize/2 - st.padding/2 - 1;
        int textHOffset = _boxsize;
        // decide on draw state
        hover = checkForHit();
        // move draw object to coordinates
        _root.pushMatrix();
        _root.translate(_x, _y);
        _root.scale(_scale);
        _root.rotate(PApplet.radians(_rotation));
        // Set default properties
        _root.rectMode(PApplet.CORNERS);
        _root.strokeWeight(st.strokeWeight);
        _root.strokeCap(PApplet.MITER);
        _root.stroke(st.shadow);
        _root.textFont(st.font, st.fontSize);
        _root.textAlign(PApplet.LEFT); 
        if(isDisabled()) {
            // disabled state
            _root.stroke(st.shadow);
            _root.fill(st.disabled);
            _root.rect(-halfbs, -halfbs, halfbs, halfbs);  
        } else if(dragged) {
            // drag/depressed state
            _root.fill(st.face);
            _root.rect(-halfbs, -halfbs, halfbs, halfbs);
            _root.noFill();
            _root.rect(-halfbs+1, -halfbs+1, halfbs-1, halfbs-1);
        } else if(hover) {
            // hover state
            _root.fill(st.scrollBar);
            _root.rect(-halfbs, -halfbs, halfbs, halfbs);
            _root.stroke(st.highlight);
            _root.noFill();
            _root.rect(-halfbs+1, -halfbs+1, halfbs-1, halfbs-1);
        } 
        else if(hasFocus()) {
            // focused default state
            _root.fill(st.scrollBar);
            _root.rect(-halfbs, -halfbs, halfbs, halfbs);
            _root.stroke(st.highlight);
            _root.noFill();
            _root.rect(-halfbs+1, -halfbs+1, halfbs-1, halfbs-1);
        } 
        else {
            // default state
            _root.fill(st.scrollBar);
            _root.rect(-halfbs, -halfbs, halfbs, halfbs);
        }
        // Now draw cross based on checked state
        int crsPad = 2+st.padding; // Set cross padding, gap between edge of box and cross
        // Calculate cross thickness
        _root.strokeWeight(PApplet.floor(PApplet.sqrt(_boxsize*0.9f)));
        // Draw cross for different states
        if(_checked) {
		        _root.stroke(st.icon);
		        // Draw cross
		        _root.line(-halfbs+crsPad,-halfbs+crsPad, halfbs-crsPad, halfbs-crsPad); 
		        _root.line(halfbs-crsPad,-halfbs+crsPad, -halfbs+crsPad, halfbs-crsPad);
        } else
        if(hover && !_disabled) {
		        _root.stroke(st.highlight);
		        // Draw cross
		        _root.line(-halfbs+crsPad,-halfbs+crsPad, halfbs-crsPad, halfbs-crsPad); 
		        _root.line(halfbs-crsPad,-halfbs+crsPad, -halfbs+crsPad, halfbs-crsPad);
        }
        // And then draw text, if set
        if(_text.length() > 0) {
		        _root.fill(st.buttonText);
		        _root.text(_text, textHOffset, textVOffset); 
        }
        _root.popMatrix();
    }
    
    /**
     * Custom checkForHit method, the central/rotate/scale point is centered on the checkBox, but
     * the actual hit zone could be much wider because of text labels.
     */
    public boolean checkForHit() { // copied from MyGUIObject
        // Because this object supports rotation the checkForHit method must also rotate its mouse coordinates
        // I have done this by offsetting by the rotation point (_x-_width/2, _y-_height/2) and then rotating
        // this value back so it can be checked against the _width and _height
        updateLocalMouse();
        int addText = 0;
        if(fixedSize) {
            addText = _width-_boxsize; // increase check zone if fixedSize is specified
        } else
        if(_text.length() > 0) {
            addText = _width; // increase check zone if there is text
        }
        if(tmouseX >= (-_boxsize/2*_scale) && tmouseY >= (-_height/2*_scale)
          && tmouseX <= ((_boxsize/2+addText)*_scale) && tmouseY <= ((_height/2)*_scale))
        {
          lastHover = true;
          return true;
        } 
        lastHover = false;
        return false;
      }
}
